/*      */ package com.zimbra.cs.mailbox;
/*      */ 
/*      */ import com.google.common.base.Joiner;
/*      */ import com.google.common.base.Objects;
/*      */ import com.google.common.base.Strings;
/*      */ import com.zimbra.client.ZMailbox;
/*      */ import com.zimbra.client.ZMailbox.Options;
/*      */ import com.zimbra.common.account.Key.AccountBy;
/*      */ import com.zimbra.common.account.Key.IdentityBy;
/*      */ import com.zimbra.common.account.ZAttrProvisioning.PrefDelegatedSendSaveTarget;
/*      */ import com.zimbra.common.localconfig.DebugConfig;
/*      */ import com.zimbra.common.mime.shim.JavaMailInternetAddress;
/*      */ import com.zimbra.common.mime.shim.JavaMailInternetHeaders;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.ArrayUtil;
/*      */ import com.zimbra.common.util.ByteUtil;
/*      */ import com.zimbra.common.util.ListUtil;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.Pair;
/*      */ import com.zimbra.common.util.StringUtil;
/*      */ import com.zimbra.common.util.SystemUtil;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.AccessManager;
/*      */ import com.zimbra.cs.account.Account;
/*      */ import com.zimbra.cs.account.AuthToken;
/*      */ import com.zimbra.cs.account.Config;
/*      */ import com.zimbra.cs.account.Domain;
/*      */ import com.zimbra.cs.account.Identity;
/*      */ import com.zimbra.cs.account.Provisioning;
/*      */ import com.zimbra.cs.filter.RuleManager;
/*      */ import com.zimbra.cs.mime.Mime;
/*      */ import com.zimbra.cs.mime.MimeVisitor;
/*      */ import com.zimbra.cs.mime.ParsedMessage;
/*      */ import com.zimbra.cs.service.AuthProvider;
/*      */ import com.zimbra.cs.service.FileUploadServlet;
/*      */ import com.zimbra.cs.service.FileUploadServlet.Upload;
/*      */ import com.zimbra.cs.service.UserServlet;
/*      */ import com.zimbra.cs.service.util.ItemId;
/*      */ import com.zimbra.cs.util.AccountUtil;
/*      */ import com.zimbra.cs.util.AccountUtil.AccountAddressMatcher;
/*      */ import com.zimbra.cs.util.BuildInfo;
/*      */ import com.zimbra.cs.util.JMSession;
/*      */ import java.io.ByteArrayInputStream;
/*      */ import java.io.IOException;
/*      */ import java.io.InputStream;
/*      */ import java.net.SocketException;
/*      */ import java.net.UnknownHostException;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Arrays;
/*      */ import java.util.Collection;
/*      */ import java.util.Collections;
/*      */ import java.util.Date;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Properties;
/*      */ import java.util.Set;
/*      */ import java.util.concurrent.ConcurrentHashMap;
/*      */ import javax.mail.Address;
/*      */ import javax.mail.MessagingException;
/*      */ import javax.mail.SendFailedException;
/*      */ import javax.mail.Session;
/*      */ import javax.mail.Transport;
/*      */ import javax.mail.internet.MimeMessage;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class MailSender
/*      */ {
/*   88 */   public static final String MSGTYPE_REPLY = String.valueOf(Flag.toChar(Flag.ID_REPLIED));
/*   89 */   public static final String MSGTYPE_FORWARD = String.valueOf(Flag.toChar(Flag.ID_FORWARDED));
/*   90 */   private static Map<String, PreSendMailListener> mPreSendMailListeners = new ConcurrentHashMap();
/*      */   
/*      */   private Boolean mSaveToSent;
/*      */   private Collection<FileUploadServlet.Upload> mUploads;
/*      */   private ItemId mOriginalMessageId;
/*      */   private String mReplyType;
/*      */   private Identity mIdentity;
/*      */   private Boolean mSendPartial;
/*   98 */   private boolean mReplyToSender = false;
/*   99 */   private boolean mRedirectMode = false;
/*  100 */   private boolean mCalendarMode = false;
/*  101 */   private boolean mSkipHeaderUpdate = false;
/*  102 */   private final List<String> mSmtpHosts = new ArrayList();
/*      */   private Session mSession;
/*  104 */   private boolean mTrackBadHosts = true;
/*  105 */   private int mCurrentHostIndex = 0;
/*  106 */   private final List<String> mRecipients = new ArrayList();
/*      */   private String mEnvelopeFrom;
/*      */   private String mDsn;
/*      */   public static final String PRE_SEND_HEADER = "X-Zimbra-Presend";
/*      */   
/*  111 */   public MailSender() { this.mSession = JMSession.getSession(); }
/*      */   
/*      */   public static enum DsnNotifyOption
/*      */   {
/*  115 */     NEVER, 
/*  116 */     SUCCESS, 
/*  117 */     FAILURE, 
/*  118 */     DELAY;
/*      */     
/*      */     private DsnNotifyOption() {} }
/*      */   
/*  122 */   public MailSender setDsnNotifyOptions(DsnNotifyOption... dsnNotifyOptions) { if ((dsnNotifyOptions == null) || (dsnNotifyOptions.length == 0)) {
/*  123 */       this.mDsn = null;
/*      */     } else {
/*  125 */       List<DsnNotifyOption> listOptions = Arrays.asList(dsnNotifyOptions);
/*  126 */       if ((listOptions.size() > 1) && (listOptions.contains(DsnNotifyOption.NEVER)))
/*  127 */         throw new IllegalArgumentException("DSN option 'NEVER' cannot be combined with others");
/*  128 */       this.mDsn = StringUtil.join(",", dsnNotifyOptions);
/*      */     }
/*  130 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setUploads(Collection<FileUploadServlet.Upload> uploads)
/*      */   {
/*  138 */     this.mUploads = uploads;
/*  139 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailSender setOriginalMessageId(ItemId id)
/*      */   {
/*  146 */     this.mOriginalMessageId = id;
/*  147 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setReplyType(String replyType)
/*      */   {
/*  157 */     this.mReplyType = replyType;
/*  158 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public MailSender setIdentity(Identity identity)
/*      */   {
/*  165 */     this.mIdentity = identity;
/*  166 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setSendPartial(boolean sendPartial)
/*      */   {
/*  174 */     this.mSendPartial = Boolean.valueOf(sendPartial);
/*  175 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setReplyToSender(boolean replyToSender)
/*      */   {
/*  184 */     this.mReplyToSender = replyToSender;
/*  185 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setRedirectMode(boolean onoff)
/*      */   {
/*  193 */     this.mRedirectMode = onoff;
/*  194 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setCalendarMode(boolean onoff)
/*      */   {
/*  205 */     this.mCalendarMode = onoff;
/*  206 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setSkipHeaderUpdate(boolean skip)
/*      */   {
/*  215 */     this.mSkipHeaderUpdate = skip;
/*  216 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setSaveToSent(boolean saveToSent)
/*      */   {
/*  225 */     this.mSaveToSent = Boolean.valueOf(saveToSent);
/*  226 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setTrackBadHosts(boolean track)
/*      */   {
/*  234 */     this.mTrackBadHosts = track;
/*  235 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setSession(Account account)
/*      */     throws ServiceException
/*      */   {
/*      */     try
/*      */     {
/*  247 */       this.mSession = JMSession.getSmtpSession(account);
/*      */     } catch (MessagingException e) {
/*  249 */       throw ServiceException.FAILURE("Unable to get SMTP session for " + account, e);
/*      */     }
/*  251 */     Domain domain = Provisioning.getInstance().getDomain(account);
/*  252 */     this.mSmtpHosts.clear();
/*  253 */     this.mSmtpHosts.addAll(JMSession.getSmtpHosts(domain));
/*  254 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setRecipients(String... recipients)
/*      */   {
/*  263 */     this.mRecipients.clear();
/*  264 */     if (recipients != null) {
/*  265 */       for (String recipient : recipients) {
/*  266 */         this.mRecipients.add(recipient);
/*      */       }
/*      */     }
/*  269 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public MailSender setEnvelopeFrom(String address)
/*      */   {
/*  280 */     this.mEnvelopeFrom = address;
/*  281 */     return this;
/*      */   }
/*      */   
/*      */   public static int getSentFolderId(Mailbox mbox, Identity identity) throws ServiceException {
/*  285 */     int folderId = 5;
/*  286 */     String sentFolder = identity.getAttr("zimbraPrefSentMailFolder", null);
/*  287 */     if (sentFolder != null) {
/*      */       try {
/*  289 */         folderId = mbox.getFolderByPath(null, sentFolder).getId();
/*      */       } catch (MailServiceException.NoSuchItemException nsie) {}
/*      */     }
/*  292 */     return folderId;
/*      */   }
/*      */   
/*      */   public static int getSentFolderId(Mailbox mbox) throws ServiceException {
/*  296 */     int folderId = 5;
/*  297 */     String sentFolder = mbox.getAccount().getAttr("zimbraPrefSentMailFolder", null);
/*  298 */     if (sentFolder != null) {
/*      */       try {
/*  300 */         folderId = mbox.getFolderByPath(null, sentFolder).getId();
/*      */       } catch (MailServiceException.NoSuchItemException nsie) {}
/*      */     }
/*  303 */     return folderId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected Boolean getSaveToSent()
/*      */   {
/*  310 */     return this.mSaveToSent;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected ItemId getOriginalMessageId()
/*      */   {
/*  317 */     return this.mOriginalMessageId;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected String getReplyType()
/*      */   {
/*  324 */     return this.mReplyType;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected Identity getIdentity()
/*      */   {
/*  331 */     return this.mIdentity;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected boolean isSendPartial()
/*      */   {
/*  338 */     if (this.mSendPartial != null) {
/*  339 */       return this.mSendPartial.booleanValue();
/*      */     }
/*  341 */     if (this.mSession != null) {
/*  342 */       String val = (String)SystemUtil.coalesce(new String[] { this.mSession.getProperty("mail.smtp.sendpartial"), this.mSession.getProperty("mail.smtps.sendpartial") });
/*      */       
/*      */ 
/*  345 */       if (val != null) {
/*  346 */         return Boolean.parseBoolean(val);
/*      */       }
/*      */     }
/*  349 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected boolean isReplyToSender()
/*      */   {
/*  356 */     return this.mReplyToSender;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected List<String> getRecipients()
/*      */   {
/*  363 */     return this.mRecipients;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected Address[] getRecipients(MimeMessage mm)
/*      */     throws MessagingException
/*      */   {
/*  371 */     Address[] rcptAddresses = null;
/*  372 */     if (this.mRecipients.isEmpty()) {
/*  373 */       rcptAddresses = mm.getAllRecipients();
/*      */     } else {
/*  375 */       rcptAddresses = new Address[this.mRecipients.size()];
/*  376 */       for (int i = 0; i < rcptAddresses.length; i++) {
/*  377 */         rcptAddresses[i] = new JavaMailInternetAddress((String)this.mRecipients.get(i));
/*      */       }
/*      */     }
/*  380 */     return rcptAddresses;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   protected Collection<FileUploadServlet.Upload> getUploads()
/*      */   {
/*  387 */     return this.mUploads;
/*      */   }
/*      */   
/*      */   public static enum ReplyForwardType {
/*  391 */     ORIGINAL, 
/*  392 */     REPLY, 
/*  393 */     FORWARD;
/*      */     
/*      */     private ReplyForwardType() {}
/*      */   }
/*      */   
/*      */   public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm, List<FileUploadServlet.Upload> uploads, ItemId origMsgId, String replyType, String identityId, boolean replyToSender)
/*      */     throws ServiceException
/*      */   {
/*  401 */     Account authuser = octxt == null ? null : octxt.getAuthenticatedUser();
/*  402 */     if (authuser == null) {
/*  403 */       authuser = mbox.getAccount();
/*      */     }
/*  405 */     Identity identity = null;
/*  406 */     if (identityId != null) {
/*  407 */       identity = Provisioning.getInstance().get(authuser, Key.IdentityBy.id, identityId);
/*      */     }
/*  409 */     return sendMimeMessage(octxt, mbox, null, mm, uploads, origMsgId, replyType, identity, replyToSender);
/*      */   }
/*      */   
/*      */   protected static class RollbackData {
/*      */     Mailbox mbox;
/*      */     ZMailbox zmbox;
/*      */     ItemId msgId;
/*      */     
/*      */     RollbackData(Mailbox m, int i) {
/*  418 */       this.mbox = m;this.msgId = new ItemId(this.mbox, i);
/*      */     }
/*      */     
/*      */     RollbackData(Message msg) {
/*  422 */       this.mbox = msg.getMailbox();this.msgId = new ItemId(msg);
/*      */     }
/*      */     
/*      */     RollbackData(ZMailbox z, Account a, String s) throws ServiceException {
/*  426 */       this.zmbox = z;this.msgId = new ItemId(s, a.getId());
/*      */     }
/*      */     
/*      */     public void rollback() {
/*      */       try {
/*  431 */         if (this.mbox != null) {
/*  432 */           this.mbox.delete(null, this.msgId.getId(), MailItem.Type.MESSAGE);
/*      */         } else {
/*  434 */           this.zmbox.deleteMessage("" + this.msgId);
/*      */         }
/*      */       } catch (ServiceException e) {
/*  437 */         ZimbraLog.smtp.warn("ignoring error while deleting saved sent message: " + this.msgId, e);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, Boolean saveToSent, MimeMessage mm, Collection<FileUploadServlet.Upload> uploads, ItemId origMsgId, String replyType, Identity identity, boolean replyToSender)
/*      */     throws ServiceException
/*      */   {
/*  448 */     this.mSaveToSent = saveToSent;
/*  449 */     this.mUploads = uploads;
/*  450 */     this.mOriginalMessageId = origMsgId;
/*  451 */     this.mReplyType = replyType;
/*  452 */     this.mIdentity = identity;
/*  453 */     this.mReplyToSender = replyToSender;
/*  454 */     return sendMimeMessage(octxt, mbox, mm);
/*      */   }
/*      */   
/*      */ 
/*      */   public ItemId sendMimeMessage(OperationContext octxt, Mailbox mbox, MimeMessage mm)
/*      */     throws ServiceException
/*      */   {
/*      */     try
/*      */     {
/*  463 */       long maxSize = Provisioning.getInstance().getConfig().getMtaMaxMessageSize();
/*  464 */       int size = mm.getSize();
/*  465 */       if (size == -1) {
/*  466 */         size = (int)ByteUtil.getDataLength(Mime.getInputStream(mm));
/*      */       }
/*      */       
/*  469 */       if ((maxSize != 0L) && (size > maxSize)) {
/*  470 */         throw MailServiceException.MESSAGE_TOO_BIG(maxSize, size);
/*      */       }
/*      */       
/*  473 */       Account acct = mbox.getAccount();
/*  474 */       Account authuser = octxt == null ? null : octxt.getAuthenticatedUser();
/*  475 */       boolean isAdminRequest = octxt == null ? false : octxt.isUsingAdminPrivileges();
/*  476 */       if (authuser == null) {
/*  477 */         authuser = acct;
/*      */       }
/*  479 */       boolean isDelegatedRequest = !acct.getId().equalsIgnoreCase(authuser.getId());
/*  480 */       boolean allowSaveToSent = true;
/*      */       
/*  482 */       if (this.mSaveToSent == null) {
/*  483 */         this.mSaveToSent = Boolean.valueOf(authuser.isPrefSaveToSent());
/*      */       } else {
/*  485 */         allowSaveToSent = this.mSaveToSent.booleanValue();
/*      */       }
/*      */       
/*      */ 
/*  489 */       int convId = -1;
/*  490 */       if ((this.mOriginalMessageId != null) && (!isDelegatedRequest) && (this.mOriginalMessageId.belongsTo(mbox))) {
/*  491 */         convId = mbox.getConversationIdFromReferent(mm, this.mOriginalMessageId.getId());
/*      */       }
/*      */       
/*      */ 
/*  495 */       updateHeaders(mm, acct, authuser, octxt, octxt != null ? octxt.getRequestIP() : null, this.mReplyToSender);
/*      */       
/*      */ 
/*  498 */       if (this.mEnvelopeFrom == null) {
/*  499 */         if (acct.isSmtpRestrictEnvelopeFrom()) {
/*  500 */           this.mEnvelopeFrom = mbox.getAccount().getName();
/*      */         }
/*      */         else {
/*  503 */           Address envAddress = mm.getSender();
/*  504 */           if (envAddress == null) {
/*  505 */             envAddress = (Address)ArrayUtil.getFirstElement(mm.getFrom());
/*      */           }
/*  507 */           if (envAddress != null) {
/*  508 */             this.mEnvelopeFrom = ((javax.mail.internet.InternetAddress)envAddress).getAddress();
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */       try
/*      */       {
/*  515 */         for (Class<? extends MimeVisitor> vclass : MimeVisitor.getMutators()) {
/*  516 */           ((MimeVisitor)vclass.newInstance()).accept(mm);
/*      */         }
/*      */       } catch (Exception e) {
/*  519 */         ZimbraLog.smtp.warn("failure to modify outbound message; aborting send", e);
/*  520 */         throw ServiceException.FAILURE("mutator error; aborting send", e);
/*      */       }
/*      */       
/*      */ 
/*  524 */       boolean hasRecipients = mm.getAllRecipients() != null;
/*  525 */       this.mSaveToSent = Boolean.valueOf(this.mSaveToSent.booleanValue() & hasRecipients);
/*      */       
/*  527 */       LinkedList<RollbackData> rollbacks = new LinkedList();
/*  528 */       Object authMailbox = isDelegatedRequest ? null : mbox;
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  537 */       Collection<Address> newAddrs = Collections.emptySet();
/*  538 */       Address[] rcptAddresses = getRecipients(mm);
/*  539 */       if ((rcptAddresses != null) && (rcptAddresses.length > 0)) {
/*  540 */         newAddrs = mbox.newContactAddrs(Arrays.asList(rcptAddresses));
/*      */       }
/*      */       
/*  543 */       ParsedMessage pm = null;
/*  544 */       ItemId returnItemId = null;
/*  545 */       if ((this.mSaveToSent.booleanValue()) && ((!isDelegatedRequest) || ((isDelegatedRequest) && ((ZAttrProvisioning.PrefDelegatedSendSaveTarget.sender == acct.getPrefDelegatedSendSaveTarget()) || (ZAttrProvisioning.PrefDelegatedSendSaveTarget.both == acct.getPrefDelegatedSendSaveTarget())))))
/*      */       {
/*      */ 
/*      */ 
/*  549 */         if (this.mIdentity == null) {
/*  550 */           this.mIdentity = Provisioning.getInstance().getDefaultIdentity(authuser);
/*      */         }
/*      */         
/*      */ 
/*  554 */         if (authMailbox == null) {
/*  555 */           authMailbox = getAuthenticatedMailbox(octxt, authuser, isAdminRequest);
/*      */         }
/*      */         Mailbox mboxSave;
/*  558 */         if ((authMailbox instanceof Mailbox)) {
/*  559 */           mboxSave = (Mailbox)authMailbox;
/*  560 */           int flags = Flag.BITMASK_FROM_ME;
/*  561 */           pm = new ParsedMessage(mm, mm.getSentDate().getTime(), mboxSave.attachmentsIndexingEnabled());
/*      */           
/*      */ 
/*  564 */           int sentFolderId = getSentFolderId(mboxSave, this.mIdentity);
/*  565 */           if (DebugConfig.disableOutgoingFilter) {
/*  566 */             DeliveryOptions dopt = new DeliveryOptions().setFolderId(sentFolderId).setNoICal(true).setFlags(flags).setConversationId(convId);
/*  567 */             Message msg = mboxSave.addMessage(octxt, pm, dopt, null);
/*  568 */             RollbackData rollback = new RollbackData(msg);
/*  569 */             rollbacks.add(rollback);
/*  570 */             returnItemId = rollback.msgId;
/*      */           } else {
/*  572 */             List<ItemId> addedItemIds = RuleManager.applyRulesToOutgoingMessage(octxt, mboxSave, pm, sentFolderId, true, flags, null, convId);
/*      */             
/*      */ 
/*  575 */             for (ItemId itemId : addedItemIds) {
/*  576 */               rollbacks.add(new RollbackData(mboxSave, itemId.getId()));
/*  577 */               if (returnItemId == null) {
/*  578 */                 returnItemId = itemId;
/*      */               }
/*      */             }
/*      */           }
/*  582 */         } else if ((authMailbox instanceof ZMailbox)) {
/*  583 */           ZMailbox zmbxSave = (ZMailbox)authMailbox;
/*  584 */           pm = new ParsedMessage(mm, mm.getSentDate().getTime(), mbox.attachmentsIndexingEnabled());
/*      */           
/*      */ 
/*  587 */           String sentFolder = this.mIdentity.getAttr("zimbraPrefSentMailFolder", "5");
/*  588 */           String msgId = zmbxSave.addMessage(sentFolder, "s", null, mm.getSentDate().getTime(), pm.getRawData(), true);
/*  589 */           RollbackData rollback = new RollbackData(zmbxSave, authuser, msgId);
/*  590 */           rollbacks.add(rollback);
/*  591 */           returnItemId = rollback.msgId;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*  598 */       if ((allowSaveToSent) && (hasRecipients) && (isDelegatedRequest) && ((ZAttrProvisioning.PrefDelegatedSendSaveTarget.owner == acct.getPrefDelegatedSendSaveTarget()) || (ZAttrProvisioning.PrefDelegatedSendSaveTarget.both == acct.getPrefDelegatedSendSaveTarget())))
/*      */       {
/*      */ 
/*  601 */         int flags = Flag.BITMASK_UNREAD | Flag.BITMASK_FROM_ME;
/*      */         
/*  603 */         OperationContext octxtTarget = new OperationContext(acct);
/*  604 */         if ((pm == null) || (pm.isAttachmentIndexingEnabled() != mbox.attachmentsIndexingEnabled())) {
/*  605 */           pm = new ParsedMessage(mm, mm.getSentDate().getTime(), mbox.attachmentsIndexingEnabled());
/*      */         }
/*  607 */         int sentFolderId = getSentFolderId(mbox, Provisioning.getInstance().getDefaultIdentity(acct));
/*  608 */         if (DebugConfig.disableOutgoingFilter) {
/*  609 */           DeliveryOptions dopt = new DeliveryOptions().setFolderId(sentFolderId).setNoICal(true).setFlags(flags).setConversationId(convId);
/*  610 */           Message msg = mbox.addMessage(octxt, pm, dopt, null);
/*  611 */           rollbacks.add(new RollbackData(msg));
/*      */         } else {
/*  613 */           List<ItemId> addedItemIds = RuleManager.applyRulesToOutgoingMessage(octxtTarget, mbox, pm, sentFolderId, true, flags, null, convId);
/*      */           
/*  615 */           for (ItemId itemId : addedItemIds) {
/*  616 */             rollbacks.add(new RollbackData(mbox, itemId.getId()));
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  622 */       if ((this.mSendPartial != null) && (this.mSession != null)) {
/*  623 */         this.mSession.getProperties().setProperty("mail.smtp.sendpartial", this.mSendPartial.toString());
/*  624 */         this.mSession.getProperties().setProperty("mail.smtps.sendpartial", this.mSendPartial.toString());
/*      */       }
/*      */       
/*      */ 
/*  628 */       if ((this.mDsn != null) && (this.mSession != null)) {
/*  629 */         this.mSession.getProperties().setProperty("mail.smtp.dsn.notify", this.mDsn);
/*      */       }
/*      */       
/*  632 */       String[] customheaders = mm.getHeader("X-Zimbra-Presend");
/*  633 */       if ((customheaders != null) && (customheaders.length > 0)) {
/*  634 */         ZimbraLog.mailbox.debug("Processing pre-send mail listeners");
/*  635 */         for (PreSendMailListener listener : mPreSendMailListeners.values()) {
/*      */           try {
/*  637 */             listener.handle(mbox, getRecipients(mm), mm);
/*      */           } catch (Exception e) {
/*  639 */             ZimbraLog.mailbox.error("pre-send mail listener %s failed ", listener.getName(), e);
/*      */           }
/*      */         }
/*  642 */         mm.removeHeader("X-Zimbra-Presend");
/*      */       }
/*      */       
/*      */ 
/*  646 */       Collection<Address> sentAddresses = sendMessage(mbox, mm, rollbacks);
/*      */       
/*      */ 
/*  649 */       if (!this.mSaveToSent.booleanValue()) {
/*      */         try {
/*  651 */           Notification.getInstance().interceptIfNecessary(mbox, mm, "send message", null);
/*      */         } catch (ServiceException e) {
/*  653 */           ZimbraLog.mailbox.error("Unable to send lawful intercept message.", e);
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*  658 */       if (this.mOriginalMessageId != null) {
/*  659 */         updateRepliedStatus(octxt, authuser, isAdminRequest, mbox);
/*      */       }
/*      */       
/*      */ 
/*  663 */       if (this.mUploads != null) {
/*  664 */         FileUploadServlet.deleteUploads(this.mUploads);
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  669 */       if ((!isDelegatedRequest) && (!sentAddresses.isEmpty()) && (octxt != null)) {
/*  670 */         assert (authMailbox == mbox);
/*      */         try {
/*  672 */           ContactRankings.increment(octxt.getAuthenticatedUser().getId(), sentAddresses);
/*      */         } catch (Exception e) {
/*  674 */           ZimbraLog.smtp.error("Failed to update contact rankings", e);
/*      */         }
/*  676 */         if (authuser.isPrefAutoAddAddressEnabled())
/*      */         {
/*  678 */           newAddrs.retainAll(sentAddresses);
/*      */           
/*      */ 
/*  681 */           List<com.zimbra.common.mime.InternetAddress> iaddrs = new ArrayList(newAddrs.size());
/*      */           
/*  683 */           for (Address addr : newAddrs) {
/*  684 */             if ((addr instanceof javax.mail.internet.InternetAddress)) {
/*  685 */               javax.mail.internet.InternetAddress iaddr = (javax.mail.internet.InternetAddress)addr;
/*  686 */               iaddrs.add(new com.zimbra.common.mime.InternetAddress(iaddr.getPersonal(), iaddr.getAddress()));
/*      */             }
/*      */           }
/*      */           try
/*      */           {
/*  691 */             mbox.createAutoContact(octxt, iaddrs);
/*      */           } catch (IOException e) {
/*  693 */             ZimbraLog.smtp.warn("Failed to auto-add contact addrs=%s", iaddrs, e);
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*  698 */       return returnItemId;
/*      */     }
/*      */     catch (SafeSendFailedException sfe) {
/*  701 */       Address[] invalidAddrs = sfe.getInvalidAddresses();
/*  702 */       Address[] validUnsentAddrs = sfe.getValidUnsentAddresses();
/*  703 */       if ((invalidAddrs != null) && (invalidAddrs.length > 0)) {
/*  704 */         StringBuilder msg = new StringBuilder("Invalid address").append(invalidAddrs.length > 1 ? "es: " : ": ");
/*  705 */         msg.append(Joiner.on(",").join(invalidAddrs)).append(".  ").append(sfe.toString());
/*      */         
/*  707 */         if (isSendPartial()) {
/*  708 */           throw MailServiceException.SEND_PARTIAL_ADDRESS_FAILURE(msg.toString(), sfe, invalidAddrs, validUnsentAddrs);
/*      */         }
/*  710 */         throw MailServiceException.SEND_ABORTED_ADDRESS_FAILURE(msg.toString(), sfe, invalidAddrs, validUnsentAddrs);
/*      */       }
/*  712 */       throw MailServiceException.SEND_FAILURE("SMTP server reported: " + sfe.getMessage(), sfe, invalidAddrs, validUnsentAddrs);
/*      */     }
/*      */     catch (IOException ioe) {
/*  715 */       throw ServiceException.FAILURE("Unable to send message", ioe);
/*      */     } catch (MessagingException me) {
/*  717 */       Exception chained = me.getNextException();
/*  718 */       if (((chained instanceof SocketException)) || ((chained instanceof UnknownHostException))) {
/*  719 */         throw MailServiceException.TRY_AGAIN("Unable to connect to the MTA", chained);
/*      */       }
/*  721 */       throw ServiceException.FAILURE("Unable to send message", me);
/*      */     }
/*      */   }
/*      */   
/*      */   private Object getAuthenticatedMailbox(OperationContext octxt, Account authuser, boolean isAdminRequest)
/*      */   {
/*  727 */     return getTargetMailbox(octxt, authuser, isAdminRequest, authuser);
/*      */   }
/*      */   
/*      */   private Object getTargetMailbox(OperationContext octxt, Account authuser, boolean isAdminRequest, Account targetUser) {
/*  731 */     if (targetUser == null) {
/*  732 */       return null;
/*      */     }
/*      */     try {
/*  735 */       if (Provisioning.onLocalServer(targetUser)) {
/*  736 */         return MailboxManager.getInstance().getMailboxByAccount(targetUser);
/*      */       }
/*  738 */       String uri = AccountUtil.getSoapUri(targetUser);
/*  739 */       if (uri == null) {
/*  740 */         return null;
/*      */       }
/*  742 */       AuthToken authToken = null;
/*  743 */       if (octxt != null) {
/*  744 */         authToken = AuthToken.getCsrfUnsecuredAuthToken(octxt.getAuthToken(false));
/*      */       }
/*  746 */       if (authToken == null) {
/*  747 */         authToken = AuthProvider.getAuthToken(authuser, isAdminRequest);
/*      */       }
/*      */       
/*  750 */       ZMailbox.Options options = new ZMailbox.Options(authToken.toZAuthToken(), uri);
/*  751 */       options.setNoSession(true);
/*  752 */       if (!targetUser.getId().equalsIgnoreCase(authuser.getId())) {
/*  753 */         options.setTargetAccount(targetUser.getId());
/*  754 */         options.setTargetAccountBy(Key.AccountBy.id);
/*      */       }
/*  756 */       return ZMailbox.getMailbox(options);
/*      */     }
/*      */     catch (Exception e) {
/*  759 */       ZimbraLog.smtp.info("could not fetch home mailbox for delegated send", e); }
/*  760 */     return null;
/*      */   }
/*      */   
/*      */ 
/*      */   public void logMessage(MimeMessage mm, String smtpHost, ItemId origMsgId, Collection<FileUploadServlet.Upload> uploads, String replyType)
/*      */   {
/*  766 */     if (ZimbraLog.smtp.isInfoEnabled()) {
/*  767 */       StringBuilder msg = new StringBuilder("Sending message");
/*  768 */       if (smtpHost != null) {
/*  769 */         msg.append(" to MTA at ").append(smtpHost);
/*      */       }
/*      */       try {
/*  772 */         msg.append(": Message-ID=" + mm.getMessageID());
/*      */       } catch (MessagingException e) {
/*  774 */         msg.append(e);
/*      */       }
/*  776 */       if (origMsgId != null) {
/*  777 */         msg.append(", origMsgId=" + origMsgId);
/*      */       }
/*  779 */       if (replyType != null) {
/*  780 */         msg.append(", replyType=" + replyType);
/*      */       }
/*  782 */       if ((uploads != null) && (uploads.size() > 0)) {
/*  783 */         msg.append(", uploads=" + uploads);
/*      */       }
/*  785 */       ZimbraLog.smtp.info(msg);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public static String formatXOrigIpHeader(String origIp)
/*      */   {
/*  795 */     return "[" + origIp + "]";
/*      */   }
/*      */   
/*      */   void updateHeaders(MimeMessage mm, Account acct, Account authuser, OperationContext octxt, String originIP, boolean replyToSender) throws MessagingException, ServiceException
/*      */   {
/*  800 */     if (this.mSkipHeaderUpdate) {
/*  801 */       return;
/*      */     }
/*  803 */     Provisioning prov = Provisioning.getInstance();
/*  804 */     if (originIP != null) {
/*  805 */       boolean addOriginatingIP = prov.getConfig().isSmtpSendAddOriginatingIP();
/*  806 */       if (addOriginatingIP) {
/*  807 */         mm.addHeader("X-Originating-IP", formatXOrigIpHeader(originIP));
/*      */       }
/*      */     }
/*      */     
/*  811 */     boolean addMailer = prov.getConfig().isSmtpSendAddMailer();
/*  812 */     if (addMailer) {
/*  813 */       String ua = octxt != null ? octxt.getUserAgent() : null;
/*  814 */       String mailer = "Zimbra " + BuildInfo.VERSION + (ua == null ? "" : new StringBuilder().append(" (").append(ua).append(")").toString());
/*  815 */       mm.addHeader("X-Mailer", mailer);
/*      */     }
/*      */     
/*  818 */     if (prov.getConfig().isSmtpSendAddAuthenticatedUser()) {
/*  819 */       mm.addHeader("X-Authenticated-User", authuser.getName());
/*      */     }
/*      */     
/*      */ 
/*  823 */     javax.mail.internet.InternetAddress from = (javax.mail.internet.InternetAddress)ArrayUtil.getFirstElement(mm.getFrom());
/*  824 */     javax.mail.internet.InternetAddress sender = (javax.mail.internet.InternetAddress)mm.getSender();
/*  825 */     if (!this.mRedirectMode)
/*      */     {
/*      */ 
/*  828 */       Pair<javax.mail.internet.InternetAddress, javax.mail.internet.InternetAddress> fromsender = getSenderHeaders(from, sender, acct, authuser, octxt != null ? octxt.isUsingAdminPrivileges() : false);
/*      */       
/*  830 */       from = (javax.mail.internet.InternetAddress)fromsender.getFirst();
/*  831 */       sender = (javax.mail.internet.InternetAddress)fromsender.getSecond();
/*      */     }
/*  833 */     mm.setFrom(from);
/*  834 */     mm.setSender(sender);
/*      */     
/*  836 */     mm.setSentDate(new Date());
/*  837 */     if (sender == null) {
/*  838 */       Address[] existingReplyTos = mm.getReplyTo();
/*  839 */       if ((existingReplyTos == null) || (existingReplyTos.length == 0)) {
/*  840 */         String replyTo = acct.getPrefReplyToAddress();
/*  841 */         if ((replyTo != null) && (!replyTo.trim().isEmpty())) {
/*  842 */           mm.setHeader("Reply-To", replyTo);
/*      */         }
/*      */       }
/*      */     }
/*  846 */     else if (replyToSender) {
/*  847 */       mm.setReplyTo(new Address[] { sender });
/*      */     }
/*      */     
/*      */ 
/*  851 */     updateReferenceHeaders(mm, octxt, authuser);
/*      */     
/*  853 */     mm.saveChanges();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public Pair<javax.mail.internet.InternetAddress, javax.mail.internet.InternetAddress> getSenderHeaders(javax.mail.internet.InternetAddress from, javax.mail.internet.InternetAddress sender, Account acct, Account authuser, boolean asAdmin)
/*      */     throws ServiceException
/*      */   {
/*  865 */     if ((from != null) && (authuser.isAllowAnyFromAddress())) {
/*  866 */       return new Pair(from, sender);
/*      */     }
/*  868 */     if ((from == null) && (sender == null)) {
/*  869 */       return new Pair(AccountUtil.getFriendlyEmailAddress(authuser), null);
/*      */     }
/*  871 */     if (Objects.equal(sender, from)) {
/*  872 */       sender = null;
/*      */     }
/*  874 */     if ((from == null) && (sender != null)) {
/*  875 */       from = sender;
/*  876 */       sender = null;
/*      */     }
/*  878 */     AccessManager amgr = AccessManager.getInstance();
/*  879 */     if ((sender == null) && ((AccountUtil.addressMatchesAccount(authuser, from.getAddress())) || (amgr.canSendAs(authuser, acct, from.getAddress(), asAdmin))))
/*      */     {
/*      */ 
/*  882 */       return new Pair(from, null);
/*      */     }
/*  884 */     if (sender != null)
/*      */     {
/*      */ 
/*  887 */       AccountUtil.AccountAddressMatcher matcher = new AccountUtil.AccountAddressMatcher(authuser, true);
/*  888 */       if (!matcher.matches(sender.getAddress())) {
/*  889 */         sender = AccountUtil.getFriendlyEmailAddress(authuser);
/*      */       }
/*      */     }
/*      */     else {
/*  893 */       sender = AccountUtil.getFriendlyEmailAddress(authuser);
/*      */     }
/*  895 */     if (this.mCalendarMode)
/*      */     {
/*  897 */       return new Pair(from, sender); }
/*  898 */     if (amgr.canSendOnBehalfOf(authuser, acct, from.getAddress(), asAdmin))
/*      */     {
/*  900 */       return new Pair(from, sender); }
/*  901 */     if (AccountUtil.isAllowedDataSourceSendAddress(authuser, from.getAddress()))
/*      */     {
/*  903 */       return new Pair(from, sender);
/*      */     }
/*      */     
/*  906 */     return new Pair(sender, null);
/*      */   }
/*      */   
/*      */   protected void updateReferenceHeaders(MimeMessage mm, OperationContext octxt, Account authuser)
/*      */   {
/*  911 */     boolean isReply = (this.mOriginalMessageId != null) && ((MSGTYPE_REPLY.equals(this.mReplyType)) || (MSGTYPE_FORWARD.equals(this.mReplyType)));
/*      */     try
/*      */     {
/*  914 */       String irt = mm.getHeader("In-Reply-To", null);
/*  915 */       String refs = mm.getHeader("References", null);
/*  916 */       String tindex = mm.getHeader("Thread-Index", null);
/*  917 */       String ttopic = mm.getHeader("Thread-Topic", null);
/*      */       
/*  919 */       if (!isReply) {
/*  920 */         if ((Strings.isNullOrEmpty(tindex)) || (Strings.isNullOrEmpty(ttopic)))
/*      */         {
/*  922 */           mm.setHeader("Thread-Topic", Threader.ThreadIndex.newThreadTopic(mm.getSubject()));
/*  923 */           mm.setHeader("Thread-Index", Threader.ThreadIndex.newThreadIndex());
/*      */         }
/*  925 */         return;
/*      */       }
/*      */       
/*  928 */       if ((!Strings.isNullOrEmpty(irt)) && (!Strings.isNullOrEmpty(refs)) && (!Strings.isNullOrEmpty(tindex)) && (!Strings.isNullOrEmpty(ttopic))) {
/*      */         return;
/*      */       }
/*      */       
/*      */       JavaMailInternetHeaders hblock;
/*  933 */       if (this.mOriginalMessageId.isLocal()) {
/*  934 */         Mailbox mbox = MailboxManager.getInstance().getMailboxByAccountId(this.mOriginalMessageId.getAccountId());
/*  935 */         Message msg = mbox.getMessageById(octxt, this.mOriginalMessageId.getId());
/*  936 */         InputStream is = msg.getContentStream();
/*      */         try {
/*  938 */           hblock = new JavaMailInternetHeaders(is);
/*      */         } finally { JavaMailInternetHeaders hblock;
/*  940 */           ByteUtil.closeStream(is);
/*      */         }
/*      */       } else {
/*  943 */         AuthToken authToken = octxt == null ? null : octxt.getAuthToken(false);
/*  944 */         if (authToken == null) {
/*  945 */           boolean isAdminRequest = octxt == null ? false : octxt.isUsingAdminPrivileges();
/*  946 */           authToken = AuthProvider.getAuthToken(authuser, isAdminRequest);
/*      */         }
/*      */         
/*  949 */         Map<String, String> params = new HashMap();
/*  950 */         params.put("fmt", "sync");params.put("body", "0");params.put("nohdr", "1");
/*  951 */         byte[] content = UserServlet.getRemoteContent(authToken, this.mOriginalMessageId, params);
/*  952 */         hblock = new JavaMailInternetHeaders(new ByteArrayInputStream(content));
/*      */       }
/*      */       
/*      */ 
/*  956 */       String parentMsgid = (String)ListUtil.getFirstElement(Mime.getReferences(hblock, "Message-ID"));
/*  957 */       if ((Strings.isNullOrEmpty(irt)) && (!Strings.isNullOrEmpty(parentMsgid))) {
/*  958 */         mm.setHeader("In-Reply-To", "<" + parentMsgid + ">");
/*      */       }
/*  960 */       if ((Strings.isNullOrEmpty(refs)) && (!Strings.isNullOrEmpty(parentMsgid))) {
/*  961 */         List<String> parentRefs = Mime.getReferences(hblock, "References");
/*      */         
/*  963 */         while (parentRefs.size() > 7) {
/*  964 */           parentRefs.remove(1);
/*      */         }
/*  966 */         parentRefs.add(parentMsgid);
/*  967 */         mm.setHeader("References", "<" + Joiner.on("> <").join(parentRefs) + ">");
/*      */       }
/*  969 */       if (Strings.isNullOrEmpty(ttopic)) {
/*  970 */         mm.setHeader("Thread-Topic", Threader.ThreadIndex.newThreadTopic(mm.getSubject()));
/*      */       }
/*  972 */       if (Strings.isNullOrEmpty(tindex)) {
/*  973 */         byte[] parentIndex = Threader.ThreadIndex.parseHeader(hblock.getHeader("Thread-Index", null));
/*  974 */         mm.setHeader("Thread-Index", parentIndex == null ? Threader.ThreadIndex.newThreadIndex() : Threader.ThreadIndex.addChild(parentIndex));
/*      */       }
/*      */     }
/*      */     catch (Exception e) {}
/*      */   }
/*      */   
/*      */   protected void updateRepliedStatus(OperationContext octxt, Account authuser, boolean isAdminRequest, Mailbox mboxPossible)
/*      */   {
/*      */     try {
/*  983 */       Object target = null;
/*  984 */       if ((mboxPossible != null) && (this.mOriginalMessageId.belongsTo(mboxPossible))) {
/*  985 */         target = mboxPossible;
/*      */       } else {
/*  987 */         target = getTargetMailbox(octxt, authuser, isAdminRequest, Provisioning.getInstance().get(Key.AccountBy.id, this.mOriginalMessageId.getAccountId()));
/*      */       }
/*      */       
/*  990 */       if ((target instanceof Mailbox)) {
/*  991 */         Mailbox mbox = (Mailbox)target;
/*  992 */         if (MSGTYPE_REPLY.equals(this.mReplyType)) {
/*  993 */           mbox.alterTag(octxt, this.mOriginalMessageId.getId(), MailItem.Type.MESSAGE, Flag.FlagInfo.REPLIED, true, null);
/*  994 */         } else if (MSGTYPE_FORWARD.equals(this.mReplyType)) {
/*  995 */           mbox.alterTag(octxt, this.mOriginalMessageId.getId(), MailItem.Type.MESSAGE, Flag.FlagInfo.FORWARDED, true, null);
/*      */         }
/*  997 */       } else if ((target instanceof ZMailbox)) {
/*  998 */         ZMailbox zmbx = (ZMailbox)target;
/*  999 */         if (MSGTYPE_REPLY.equals(this.mReplyType)) {
/* 1000 */           zmbx.tagMessage(this.mOriginalMessageId.toString(), "" + Flag.ID_REPLIED, true);
/* 1001 */         } else if (MSGTYPE_FORWARD.equals(this.mReplyType)) {
/* 1002 */           zmbx.tagMessage(this.mOriginalMessageId.toString(), "" + Flag.ID_FORWARDED, true);
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (ServiceException e) {}
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected Collection<Address> sendMessage(Mailbox mbox, MimeMessage mm, Collection<RollbackData> rollbacks)
/*      */     throws MailSender.SafeMessagingException, IOException
/*      */   {
/* 1016 */     HashSet<Address> sentAddresses = new HashSet();
/* 1017 */     this.mCurrentHostIndex = 0;
/* 1018 */     String hostname = getNextHost();
/*      */     
/*      */     try
/*      */     {
/* 1022 */       Address[] rcptAddresses = getRecipients(mm);
/*      */       
/* 1024 */       if ((rcptAddresses == null) || (rcptAddresses.length == 0)) {
/* 1025 */         throw new SendFailedException("No recipient addresses");
/*      */       }
/*      */       for (;;) {
/*      */         try {
/* 1029 */           logMessage(mm, hostname, this.mOriginalMessageId, this.mUploads, this.mReplyType);
/* 1030 */           if (hostname != null) {
/* 1031 */             sendMessageToHost(hostname, mm, rcptAddresses);
/*      */           } else {
/* 1033 */             Transport.send(mm, rcptAddresses);
/*      */           }
/* 1035 */           Collections.addAll(sentAddresses, rcptAddresses);
/*      */         }
/*      */         catch (SendFailedException sfe) {
/* 1038 */           throw sfe;
/*      */         } catch (MessagingException e) {
/* 1040 */           Exception chained = e.getNextException();
/* 1041 */           if (((chained instanceof SocketException)) || ((chained instanceof UnknownHostException))) {
/* 1042 */             String hostString = hostname != null ? " " + hostname : "";
/* 1043 */             ZimbraLog.smtp.warn("Unable to connect to SMTP server%s: %s.", new Object[] { hostString, chained.toString() });
/*      */             
/* 1045 */             if (this.mTrackBadHosts) {
/* 1046 */               JMSession.markSmtpHostBad(hostname);
/*      */             }
/* 1048 */             hostname = getNextHost();
/* 1049 */             if (hostname == null) {
/* 1050 */               throw e;
/*      */             }
/* 1052 */             ZimbraLog.smtp.info("Attempting to send to %s.", new Object[] { hostname });
/*      */           } else {
/* 1054 */             throw e;
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     catch (SendFailedException e) {
/* 1060 */       if (isSendPartial()) {
/* 1061 */         throw new SafeSendFailedException(e);
/*      */       }
/* 1063 */       for (RollbackData rdata : rollbacks) {
/* 1064 */         if (rdata != null) {
/* 1065 */           rdata.rollback();
/*      */         }
/*      */       }
/*      */       
/* 1069 */       throw new SafeSendFailedException(e);
/*      */     } catch (MessagingException e) {
/* 1071 */       for (RollbackData rdata : rollbacks) {
/* 1072 */         if (rdata != null) {
/* 1073 */           rdata.rollback();
/*      */         }
/*      */       }
/* 1076 */       throw new SafeMessagingException(e);
/*      */     } catch (RuntimeException e) {
/* 1078 */       for (RollbackData rdata : rollbacks) {
/* 1079 */         if (rdata != null) {
/* 1080 */           rdata.rollback();
/*      */         }
/*      */       }
/* 1083 */       throw e;
/*      */     }
/* 1085 */     return sentAddresses;
/*      */   }
/*      */   
/*      */   private String getNextHost() {
/* 1089 */     if ((this.mSession != null) && (this.mCurrentHostIndex < this.mSmtpHosts.size())) {
/* 1090 */       return (String)this.mSmtpHosts.get(this.mCurrentHostIndex++);
/*      */     }
/* 1092 */     return null;
/*      */   }
/*      */   
/*      */   private void sendMessageToHost(String hostname, MimeMessage mm, Address[] rcptAddresses) throws MessagingException
/*      */   {
/* 1097 */     this.mSession.getProperties().setProperty("mail.smtp.host", hostname);
/* 1098 */     if (this.mEnvelopeFrom != null) {
/* 1099 */       this.mSession.getProperties().setProperty("mail.smtp.from", this.mEnvelopeFrom);
/*      */     }
/* 1101 */     ZimbraLog.smtp.debug("Sending message %s to SMTP host %s with properties: %s", new Object[] { mm.getMessageID(), hostname, this.mSession.getProperties() });
/*      */     
/* 1103 */     Transport transport = this.mSession.getTransport("smtp");
/*      */     try {
/* 1105 */       transport.connect();
/* 1106 */       transport.sendMessage(mm, rcptAddresses);
/*      */     } finally {
/* 1108 */       transport.close();
/*      */     }
/*      */   }
/*      */   
/*      */   private void checkMTAConnectionToHost(String hostname) throws MessagingException {
/* 1113 */     this.mSession.getProperties().setProperty("mail.smtp.host", hostname);
/* 1114 */     if (this.mEnvelopeFrom != null) {
/* 1115 */       this.mSession.getProperties().setProperty("mail.smtp.from", this.mEnvelopeFrom);
/*      */     }
/* 1117 */     ZimbraLog.smtp.debug("Testing connection to SMTP host %s with properties: %s", new Object[] { hostname, this.mSession.getProperties() });
/*      */     
/* 1119 */     Transport transport = this.mSession.getTransport("smtp");
/*      */     try {
/* 1121 */       transport.connect();
/*      */     } finally {
/* 1123 */       transport.close();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void checkMTAConnection()
/*      */     throws ServiceException
/*      */   {
/* 1134 */     MessagingException connectError = null;
/* 1135 */     this.mCurrentHostIndex = 0;
/*      */     String hostname;
/* 1137 */     while ((hostname = getNextHost()) != null) {
/*      */       try {
/* 1139 */         checkMTAConnectionToHost(hostname);
/* 1140 */         return;
/*      */       } catch (MessagingException e) {
/* 1142 */         Exception chained = e.getNextException();
/* 1143 */         if (((chained instanceof SocketException)) || ((chained instanceof UnknownHostException))) {
/* 1144 */           if (connectError == null) {
/* 1145 */             connectError = e;
/*      */           }
/* 1147 */           String hostString = hostname != null ? " " + hostname : "";
/* 1148 */           ZimbraLog.smtp.warn("Unable to connect to SMTP server%s: %s.", new Object[] { hostString, chained.toString() });
/* 1149 */           if (this.mTrackBadHosts) {
/* 1150 */             JMSession.markSmtpHostBad(hostname);
/*      */           }
/*      */         } else {
/* 1153 */           throw ServiceException.FAILURE("unexpected error during MTA connection check", e);
/*      */         }
/*      */       }
/*      */     }
/* 1157 */     throw ServiceException.FAILURE("unable to connect to MTA", connectError);
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static void relayMessage(MimeMessage mm)
/*      */     throws MessagingException, ServiceException
/*      */   {
/* 1166 */     Session session = JMSession.getRelaySession();
/* 1167 */     ZimbraLog.smtp.debug("Sending message %s with properties: %s", new Object[] { mm.getMessageID(), session.getProperties() });
/*      */     
/* 1169 */     Transport transport = session.getTransport("smtp");
/*      */     try {
/* 1171 */       transport.connect();
/* 1172 */       transport.sendMessage(mm, mm.getAllRecipients());
/*      */     } finally {
/* 1174 */       transport.close();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */   public static class SafeMessagingException
/*      */     extends MessagingException
/*      */   {
/*      */     private static final long serialVersionUID = -4652297855877992478L;
/*      */     
/*      */     private final MessagingException mMex;
/*      */     
/*      */     public SafeMessagingException(MessagingException mex)
/*      */     {
/* 1188 */       this.mMex = mex;
/* 1189 */       setStackTrace(this.mMex.getStackTrace());
/*      */     }
/*      */     
/*      */     public String getMessage()
/*      */     {
/* 1194 */       return this.mMex.getMessage();
/*      */     }
/*      */     
/*      */     public synchronized Exception getNextException()
/*      */     {
/* 1199 */       return this.mMex.getNextException();
/*      */     }
/*      */     
/*      */     public synchronized String toString()
/*      */     {
/* 1204 */       StringBuffer sb = new StringBuffer();
/* 1205 */       appendException(sb, this);
/* 1206 */       Exception n = this.mMex.getNextException();
/* 1207 */       int more = 0;
/* 1208 */       while (n != null) {
/* 1209 */         if (more == 0) {
/* 1210 */           sb.append("; chained exception is:\n\t");
/* 1211 */           appendException(sb, n);
/*      */         }
/* 1213 */         if (!(n instanceof MessagingException)) break;
/* 1214 */         MessagingException mex = (MessagingException)n;
/* 1215 */         n = mex.getNextException();
/* 1216 */         if (n != null) {
/* 1217 */           more++;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/* 1224 */       if (more > 0) {
/* 1225 */         sb.append("\n\t(").append(more).append(" more chained exception");
/* 1226 */         if (more > 1)
/* 1227 */           sb.append('s');
/* 1228 */         sb.append(')');
/*      */       }
/* 1230 */       return sb.toString();
/*      */     }
/*      */     
/*      */     private static StringBuffer appendException(StringBuffer sb, Exception e)
/*      */     {
/* 1235 */       sb.append(e.getClass().getName());
/* 1236 */       String message = e.getLocalizedMessage();
/* 1237 */       if (message != null) {
/* 1238 */         sb.append(": ").append(message);
/*      */       }
/* 1240 */       return sb;
/*      */     }
/*      */   }
/*      */   
/*      */   public static class SafeSendFailedException extends MailSender.SafeMessagingException {
/*      */     private static final long serialVersionUID = 5625565177360027934L;
/*      */     private final SendFailedException mSfe;
/*      */     
/*      */     public SafeSendFailedException(SendFailedException sfe) {
/* 1249 */       super();
/* 1250 */       this.mSfe = sfe;
/*      */     }
/*      */     
/*      */     public Address[] getInvalidAddresses() {
/* 1254 */       return this.mSfe.getInvalidAddresses();
/*      */     }
/*      */     
/*      */     public Address[] getValidSentAddresses() {
/* 1258 */       return this.mSfe.getValidSentAddresses();
/*      */     }
/*      */     
/*      */     public Address[] getValidUnsentAddresses() {
/* 1262 */       return this.mSfe.getValidUnsentAddresses();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public static final String X_ORIGINATING_IP = "X-Originating-IP";
/*      */   
/*      */   private static final String X_MAILER = "X-Mailer";
/*      */   
/*      */   public static final String X_AUTHENTICATED_USER = "X-Authenticated-User";
/*      */   
/*      */   public static void registerPreSendMailListener(PreSendMailListener listener)
/*      */   {
/* 1276 */     String name = listener.getName();
/* 1277 */     if (!mPreSendMailListeners.containsKey(name)) {
/* 1278 */       mPreSendMailListeners.put(name, listener);
/* 1279 */       ZimbraLog.extensions.info("registered SendMailListener " + name);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   public static void unregisterPreSendMailListener(PreSendMailListener listener)
/*      */   {
/* 1288 */     for (Iterator<String> it = mPreSendMailListeners.keySet().iterator(); it.hasNext();) {
/* 1289 */       String name = (String)it.next();
/* 1290 */       if (name.equalsIgnoreCase(listener.getName())) {
/* 1291 */         it.remove();
/* 1292 */         ZimbraLog.extensions.info("unregistered SendMailListener " + name);
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   public static abstract interface PreSendMailListener
/*      */   {
/*      */     public abstract void handle(Mailbox paramMailbox, Address[] paramArrayOfAddress, MimeMessage paramMimeMessage);
/*      */     
/*      */     public abstract String getName();
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/MailSender.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */